#include "VMemory.h"
#include "VirtualNDK.h"
#define UC_MEM_ALIGN  0x1000

#define PF_X  0x1  // Executable
#define PF_W  0x2  // Writable
#define PF_R  0x4  // Readable
void align(uint64_t* addr, uint32_t* size, bool growl)
{

	uint64_t to = UC_MEM_ALIGN;
	uint64_t mask = 0xFFFFFFFFFFFFFFFF ^ (to - 1);

	uint64_t  right = *addr + *size;
	right = (right + to - 1)&mask;
	*addr &= mask;
	*size = right - *addr;
	if (growl)
		*size = (*size + to - 1)& mask;

	return;
}



VMemory::VMemory(VirtualNDK* vndk):
	vndk(vndk),
	counter_memory(BASE_ADDR),
	counter_stack(STACK_ADDR + STACK_SIZE)
{

}

VMemory::~VMemory()
{
}



uint64_t VMemory::mem_reserve(int size)
{
	uint32_t aligned = size;
	uint64_t addr = 0;
	align(&addr, &aligned, true);
	uint64_t  ret = counter_memory;
	counter_memory += aligned;
	return ret;

}

void VMemory::mem_map(uint64_t address, size_t size, uint32_t prot)
{
	uc_err err = uc_mem_map(vndk->uc, address, size, prot);
	if (err) logger("Failed on mem_map() with error returned: %u (%s)\n", err, uc_strerror(err));
}

void VMemory::mem_protect(uint64_t address, size_t size, uint32_t prot)
{
	uc_err err = uc_mem_protect(vndk->uc, address, size, prot);
	if (err) logger("Failed on mem_protect() with error returned: %u (%s)\n", err, uc_strerror(err));
}

void VMemory::mem_write(uint64_t address, const void * bytes, size_t size)
{
	uc_err err = uc_mem_write(vndk->uc, address, bytes, size);
	if (err) logger("Failed on mem_write() with error returned: %u (%s)\n", err, uc_strerror(err));
}

void VMemory::mem_read(uint64_t address, void * bytes, size_t size)
{
	uc_err err = uc_mem_read(vndk->uc, address, bytes, size);
	if (err) logger("Failed on mem_read() with error returned: %u (%s)\n", err, uc_strerror(err));
}

void VMemory::mem_set(uint64_t dst, int val, size_t size)
{
	BYTE* bytes = new BYTE[size]{ 0 };
	memset(bytes, val, size);
	uc_err err = uc_mem_write(vndk->uc, dst, bytes, size);
	if (err) logger("Failed on mem_set() with error returned: %u (%s)\n", err, uc_strerror(err));
	delete bytes;
	return;


}



